package com.xyy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyy.common.PageResult;
import com.xyy.dto.DoctorQueryDTO;
import com.xyy.entity.Doctor;
import com.xyy.mapper.DoctorMapper;
import com.xyy.service.DoctorService;
import com.xyy.service.EmailService;
import com.xyy.service.FileService;
import com.xyy.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * 医生服务实现类
 */
@Slf4j
@Service
public class DoctorServiceImpl extends ServiceImpl<DoctorMapper, Doctor> implements DoctorService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private EmailService emailService;

    @Autowired
    private FileService fileService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public Map<String, Object> register(Doctor doctor) {
        // 验证用户名是否已存在
        if (checkUsernameExists(doctor.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }

        // 验证手机号是否已存在
        if (checkPhoneExists(doctor.getPhone())) {
            throw new RuntimeException("手机号已存在");
        }

        // 验证邮箱是否已存在
        if (checkEmailExists(doctor.getEmail())) {
            throw new RuntimeException("邮箱已存在");
        }

        // 设置密码加密
        doctor.setPassword(passwordEncoder.encode(doctor.getPassword()));
        doctor.setDeleted(0);

        // 保存医生信息
        save(doctor);

        // 生成JWT token
        String token = jwtUtil.generateToken(doctor.getUsername(), doctor.getId());

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("doctor", doctor);
        result.put("message", "注册成功");
        return result;
    }

    @Override
    public Map<String, Object> login(Doctor doctor) {
        // 根据用户名查询医生
        Doctor existingDoctor = getByUsername(doctor.getUsername());
        if (existingDoctor == null) {
            throw new RuntimeException("用户名不存在");
        }

        // 验证密码
        if (!passwordEncoder.matches(doctor.getPassword(), existingDoctor.getPassword())) {
            throw new RuntimeException("密码错误");
        }

        // 检查是否被删除
        if (existingDoctor.getDeleted() != null && existingDoctor.getDeleted() == 1) {
            throw new RuntimeException("账户已被删除");
        }

        // 更新最后登录时间
        updateLastLoginInfo(existingDoctor.getId(), null);

        // 生成JWT token
        String token = jwtUtil.generateToken(existingDoctor.getUsername(), existingDoctor.getId());

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("doctor", existingDoctor);
        result.put("message", "登录成功");
        return result;
    }

    @Override
    public void sendEmailCode(String email, String username) {
        // 如果提供了用户名，验证邮箱是否属于该用户
        if (username != null && !username.trim().isEmpty()) {
            Doctor doctor = getByUsername(username);
            if (doctor == null) {
                throw new RuntimeException("用户名不存在");
            }
            if (!email.equals(doctor.getEmail())) {
                throw new RuntimeException("用户名与邮箱不匹配");
            }
        } else {
            // 如果没有提供用户名，验证邮箱是否存在于系统中
            Doctor doctor = getDoctorByEmail(email);
            if (doctor == null) {
                throw new RuntimeException("邮箱不存在于系统中");
            }
        }
        
        // 生成6位随机验证码
        String emailCode = generateEmailCode();
        
        // 存储验证码到Redis，设置5分钟过期
        String key = "email_code:" + email;
        redisTemplate.opsForValue().set(key, emailCode, 5, TimeUnit.MINUTES);
        
        // 发送邮件
        emailService.sendEmailCode(email, emailCode);
        
        log.info("邮箱验证码发送成功: email={}, username={}", email, username);
    }

    @Override
    public void resetPassword(Doctor doctor) {
        // 验证用户名和邮箱是否匹配
        validateDoctorEmail(doctor.getUsername(), doctor.getEmail());

        // 验证邮箱验证码
        if (!verifyEmailCode(doctor.getUsername(), doctor.getEmail(), doctor.getEmailCode())) {
            throw new RuntimeException("验证码错误或已过期");
        }

        // 更新密码
        Doctor existingDoctor = getByUsername(doctor.getUsername());
        if (existingDoctor == null) {
            throw new RuntimeException("用户不存在");
        }

        LambdaUpdateWrapper<Doctor> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Doctor::getId, existingDoctor.getId())
                    .set(Doctor::getPassword, passwordEncoder.encode(doctor.getPassword()));
        update(updateWrapper);

        log.info("密码重置成功: username={}", doctor.getUsername());
    }

    @Override
    public Doctor getDoctorByUsername(String username) {
        return getByUsername(username);
    }

    @Override
    public Doctor getDoctorByEmail(String email) {
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getEmail, email)
                    .eq(Doctor::getDeleted, 0);
        return getOne(queryWrapper);
    }

    @Override
    public Doctor getDoctorByPhone(String phone) {
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getPhone, phone)
                    .eq(Doctor::getDeleted, 0);
        return getOne(queryWrapper);
    }

    @Override
    public void updateLastLoginInfo(Long doctorId, String ip) {
        // 由于数据库表缺少last_login_time和last_login_ip字段，暂时不更新登录信息
        log.info("医生登录信息更新: doctorId={}, ip={}", doctorId, ip);
    }

    @Override
    public void validateDoctorEmail(String username, String email) {
        Doctor doctor = getByUsername(username);
        if (doctor == null) {
            throw new RuntimeException("用户名不存在");
        }

        if (!email.equals(doctor.getEmail())) {
            throw new RuntimeException("用户名与邮箱不匹配");
        }
    }

    @Override
    public boolean verifyEmailCode(String username, String email, String emailCode) {
        // 从Redis中获取存储的验证码
        String key = "email_code:" + email;
        String storedCode = redisTemplate.opsForValue().get(key);
        
        if (storedCode == null) {
            log.warn("验证码不存在或已过期: email={}", email);
            return false;
        }
        
        // 验证验证码
        boolean isValid = storedCode.equals(emailCode);
        
        if (isValid) {
            // 验证成功后删除验证码
            redisTemplate.delete(key);
            log.info("邮箱验证码验证成功: username={}, email={}", username, email);
        } else {
            log.warn("邮箱验证码验证失败: username={}, email={}, inputCode={}, storedCode={}", 
                    username, email, emailCode, storedCode);
        }
        
        return isValid;
    }

    @Override
    public void updateDoctorAvatar(Long doctorId, String avatarUrl) {
        LambdaUpdateWrapper<Doctor> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Doctor::getId, doctorId)
                    .set(Doctor::getAvatar, avatarUrl);
        update(updateWrapper);
        
        log.info("医生头像更新成功: doctorId={}, avatarUrl={}", doctorId, avatarUrl);
    }

    @Override
    public void createDoctor(Doctor createDTO) {
        // 验证用户名是否已存在
        if (checkUsernameExists(createDTO.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }

        // 验证手机号是否已存在
        if (checkPhoneExists(createDTO.getPhone())) {
            throw new RuntimeException("手机号已存在");
        }

        // 验证邮箱是否已存在
        if (checkEmailExists(createDTO.getEmail())) {
            throw new RuntimeException("邮箱已存在");
        }

        // 创建医生实体
        Doctor doctor = new Doctor();
        doctor.setUsername(createDTO.getUsername());
        doctor.setPassword(passwordEncoder.encode(createDTO.getPassword()));
        doctor.setRealName(createDTO.getRealName());
        doctor.setPhone(createDTO.getPhone());
        doctor.setEmail(createDTO.getEmail());
        doctor.setGender(createDTO.getGender());
        doctor.setAddress(createDTO.getAddress());
        doctor.setPracticeScope(createDTO.getPracticeScope());
        doctor.setDeleted(0);

        // 保存医生信息
        save(doctor);

        log.info("医生创建成功: username={}", createDTO.getUsername());
    }

    @Override
    public void updateDoctor(Doctor doctor) {
        // 检查医生是否存在
        Doctor existingDoctor = getById(doctor.getId());
        if (existingDoctor == null) {
            throw new RuntimeException("医生不存在");
        }

        // 检查是否被删除
        if (existingDoctor.getDeleted() != null && existingDoctor.getDeleted() == 1) {
            throw new RuntimeException("医生已被删除");
        }

        // 检查用户名唯一性（排除自己）
        if (!existingDoctor.getUsername().equals(doctor.getUsername())) {
            LambdaQueryWrapper<Doctor> usernameQuery = new LambdaQueryWrapper<>();
            usernameQuery.eq(Doctor::getUsername, doctor.getUsername())
                        .eq(Doctor::getDeleted, 0)
                        .ne(Doctor::getId, doctor.getId());
            if (count(usernameQuery) > 0) {
                throw new RuntimeException("用户名已存在");
            }
        }

        // 检查手机号唯一性（排除自己）
        if (!existingDoctor.getPhone().equals(doctor.getPhone())) {
            LambdaQueryWrapper<Doctor> phoneQuery = new LambdaQueryWrapper<>();
            phoneQuery.eq(Doctor::getPhone, doctor.getPhone())
                     .eq(Doctor::getDeleted, 0)
                     .ne(Doctor::getId, doctor.getId());
            if (count(phoneQuery) > 0) {
                throw new RuntimeException("手机号已存在");
            }
        }

        // 检查邮箱唯一性（排除自己）
        if (!existingDoctor.getEmail().equals(doctor.getEmail())) {
            LambdaQueryWrapper<Doctor> emailQuery = new LambdaQueryWrapper<>();
            emailQuery.eq(Doctor::getEmail, doctor.getEmail())
                     .eq(Doctor::getDeleted, 0)
                     .ne(Doctor::getId, doctor.getId());
            if (count(emailQuery) > 0) {
                throw new RuntimeException("邮箱已存在");
            }
        }

        updateById(doctor);

        log.info("医生信息更新成功: doctorId={}", doctor.getId());
    }

    @Override
    public void deleteDoctor(Long doctorId) {
        // 软删除医生
        LambdaUpdateWrapper<Doctor> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Doctor::getId, doctorId)
                    .set(Doctor::getDeleted, 1);
        update(updateWrapper);

        log.info("医生删除成功: doctorId={}", doctorId);
    }

    @Override
    public void batchDeleteDoctor(List<Long> doctorIds) {
        // 批量软删除医生
        LambdaUpdateWrapper<Doctor> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(Doctor::getId, doctorIds)
                    .set(Doctor::getDeleted, 1);
        update(updateWrapper);

        log.info("批量删除医生成功: doctorIds={}", doctorIds);
    }

    @Override
    public void restoreDoctor(Long doctorId) {
        // 恢复医生
        LambdaUpdateWrapper<Doctor> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Doctor::getId, doctorId)
                    .set(Doctor::getDeleted, 0);
        update(updateWrapper);

        log.info("医生恢复成功: doctorId={}", doctorId);
    }

    @Override
    public PageResult<Doctor> pageQuery(Doctor doctor, Integer current, Integer size) {
        // 构建查询条件
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getDeleted, 0); // 只查询未删除的

        // 添加查询条件
        if (StringUtils.hasText(doctor.getRealName())) {
            queryWrapper.like(Doctor::getRealName, doctor.getRealName());
        }
        if (StringUtils.hasText(doctor.getPhone())) {
            queryWrapper.like(Doctor::getPhone, doctor.getPhone());
        }
        if (StringUtils.hasText(doctor.getEmail())) {
            queryWrapper.like(Doctor::getEmail, doctor.getEmail());
        }
        if (doctor.getGender() != null) {
            queryWrapper.eq(Doctor::getGender, doctor.getGender());
        }
        if (StringUtils.hasText(doctor.getPracticeScope())) {
            queryWrapper.like(Doctor::getPracticeScope, doctor.getPracticeScope());
        }
        if (StringUtils.hasText(doctor.getHospitalName())) {
            queryWrapper.eq(Doctor::getHospitalName, doctor.getHospitalName());
        }

        // 按创建时间倒序
        queryWrapper.orderByDesc(Doctor::getCreateTime);

        // 分页查询
        Page<Doctor> page = new Page<>(current, size);
        Page<Doctor> result = page(page, queryWrapper);

        return new PageResult<Doctor>(result.getRecords(), result.getTotal(), Long.valueOf(current), Long.valueOf(size));
    }

    @Override
    public PageResult<Doctor> pageQueryDeleted(Integer current, Integer size) {
        // 使用自定义方法查询已删除的医生，避免@TableLogic的影响
        List<Doctor> deletedDoctors = baseMapper.selectDeletedDoctors();
        Long total = baseMapper.countDeletedDoctors();
        
        // 手动分页
        int start = (current - 1) * size;
        int end = Math.min(start + size, deletedDoctors.size());
        
        List<Doctor> pageRecords = deletedDoctors.subList(start, end);
        
        return new PageResult<Doctor>(pageRecords, total, Long.valueOf(current), Long.valueOf(size));
    }

    @Override
    public List<Doctor> getDeletedDoctors() {
        // 使用自定义方法查询已删除的医生，避免@TableLogic的影响
        return baseMapper.selectDeletedDoctors();
    }

    @Override
    public Long countDeletedDoctors() {
        // 使用自定义方法统计已删除的医生，避免@TableLogic的影响
        return baseMapper.countDeletedDoctors();
    }

    @Override
    public List<String> getAllHospitalNames() {
        // 查询所有level为1的管理员的real_name字段作为医院名称
        log.info("开始查询所有医院名称");
        List<String> hospitals = baseMapper.selectAllHospitalNames();
        log.info("查询到的医院名称: {}", hospitals);
        return hospitals;
    }

    @Override
    public PageResult<Doctor> pageQueryForAdmin(DoctorQueryDTO queryDTO, Integer current, Integer size) {
        // 构建查询条件
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getDeleted, 0); // 只查询未删除的

        // 添加查询条件
        if (StringUtils.hasText(queryDTO.getRealName())) {
            queryWrapper.like(Doctor::getRealName, queryDTO.getRealName());
        }
        if (StringUtils.hasText(queryDTO.getPracticeScope())) {
            queryWrapper.like(Doctor::getPracticeScope, queryDTO.getPracticeScope());
        }
        if (StringUtils.hasText(queryDTO.getHospitalName())) {
            queryWrapper.eq(Doctor::getHospitalName, queryDTO.getHospitalName());
        }

        // 按创建时间倒序
        queryWrapper.orderByDesc(Doctor::getCreateTime);

        // 分页查询
        Page<Doctor> page = new Page<>(current, size);
        Page<Doctor> result = page(page, queryWrapper);

        return new PageResult<Doctor>(result.getRecords(), result.getTotal(), Long.valueOf(current), Long.valueOf(size));
    }

    @Override
    public Doctor getDoctorInfoForReset(String username) {
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getUsername, username)
                    .eq(Doctor::getDeleted, 0);
        return getOne(queryWrapper);
    }

    @Override
    public String getEmailByUsername(String username) {
        Doctor doctor = getDoctorInfoForReset(username);
        if (doctor == null) {
            throw new RuntimeException("医生不存在");
        }
        return doctor.getEmail();
    }

    @Override
    public String uploadAvatar(Long doctorId, String filename, byte[] fileBytes) throws IOException {
        // 上传文件到文件服务
        String avatarUrl = fileService.uploadFile(fileBytes, filename, "avatar");
        
        // 更新医生头像
        updateDoctorAvatar(doctorId, avatarUrl);
        
        return avatarUrl;
    }

    // 私有方法

    private boolean checkUsernameExists(String username) {
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getUsername, username)
                    .eq(Doctor::getDeleted, 0);
        return count(queryWrapper) > 0;
    }

    private boolean checkPhoneExists(String phone) {
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getPhone, phone)
                    .eq(Doctor::getDeleted, 0);
        return count(queryWrapper) > 0;
    }

    private boolean checkEmailExists(String email) {
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getEmail, email)
                    .eq(Doctor::getDeleted, 0);
        return count(queryWrapper) > 0;
    }

    private Doctor getByUsername(String username) {
        LambdaQueryWrapper<Doctor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Doctor::getUsername, username)
                    .eq(Doctor::getDeleted, 0);
        return getOne(queryWrapper);
    }

    private void updateLoginInfo(Long doctorId, HttpServletRequest request) {
        LambdaUpdateWrapper<Doctor> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Doctor::getId, doctorId);
        update(updateWrapper);
    }

    private String generateVerificationCode() {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(10));
        }
        return code.toString();
    }

    private String generateEmailCode() {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            code.append(random.nextInt(10));
        }
        return code.toString();
    }
} 